-- 写一会儿就想加一点新功能 真是服了

local prefab_id = "webbert_skitter"

local assets =
{
    Asset( "ANIM", "anim/fused_shadeling_bomb.zip"),
}

local prefabs =
{
}

---comment
---@param number number
---@param x number
---@param y number
---@param z number
local function SpawnStrikeFX(number,x,y,z)
    for i = 1,number do
        local fx = SpawnPrefab("shadowstrike_slash_fx")
        fx.Transform:SetScale(0.1*math.random(3,12),0.1*math.random(3,12),0.1*math.random(3,12))
        fx.Transform:SetPosition(x,y+0.3*math.random(1,5),z)
        fx.Transform:SetRotation(math.random(0,360))
    end
end

---不然为什么叫烦人的小妖精呢
---@param elf ent
---@param bh string # 行为
---@param which string # 行为中的哪一个动作
---@param chance number # 几率触发
---@param playername string|nil
local function Annoy(elf,bh,which,chance,playername)
    if math.random()>chance then
        return
    end
    local tbl = STRINGS.MOD_WEBBER_THE_TRAINER.elf.hobby[elf.components.webbert_skitter_misc.hobby]
    local content_tbl = tbl.content and tbl.content[bh] and tbl.content[bh][which]
    if content_tbl then
        local len = #content_tbl
        local content = nil
        if len>1 then
            content = content_tbl[math.random(1,len)]
        else
            content = content_tbl[1]
        end
        if content then
            elf.components.talker:Say(playername and subfmt(content,{playername = playername}) or content)
        end
    end
end

---@class webbert_skitter_helps # 只有自动目标写这里面
---@field testfn fun(elf:ent,tar:ent):boolean # 测试目标能否被小虫操作
---@field actionfn fun(elf:ent,tar:ent)

---@type table<string,webbert_skitter_helps>
local helps = {
    grass = {
        testfn = function(elf,tar)
            if tar and tar:IsValid() and tar.components.pickable and tar.components.pickable:CanBePicked() then
                return true
            end
            return false
        end,
        actionfn = function(elf,tar)
            local success,loot = tar.components.pickable:Pick(elf)
            local x,y,z = tar:GetPosition():Get()
            SpawnStrikeFX(2,x,y,z)
            if loot and type(loot) == 'table' then
                if loot[1] then
                    -- elf.components.webbert_skitter_inventory:GiveSimpleItem(loot[1])
                    elf.components.container:GiveItem(loot[1])
                end
            end
        end
    },
    sapling = {
        testfn = function(elf,tar)
            if tar and tar:IsValid() and tar.components.pickable and tar.components.pickable:CanBePicked() then
                return true
            end
            return false
        end,
        actionfn = function(elf,tar)
            local success,loot = tar.components.pickable:Pick(elf)
            local x,y,z = tar:GetPosition():Get()
            SpawnStrikeFX(2,x,y,z)
            if loot and type(loot) == 'table' then
                if loot[1] then
                    -- elf.components.webbert_skitter_inventory:GiveSimpleItem(loot[1])
                    elf.components.container:GiveItem(loot[1])
                end
            end
        end
    },
    ----------------------
    help_farm = {
        testfn = function (elf, tar)
            return tar and tar:IsValid() and tar:HasTag('tendable_farmplant') and tar.components.farmplanttendable ~= nil and tar.components.farmplantstress ~= nil
            -- return tar and tar:IsValid() and tar.components.farmplantstress and tar.components.farmplantstress.stressors and next(tar.components.farmplantstress.stressors) ~= nil
        end,
        actionfn = function (elf, tar)
            tar.components.farmplanttendable:TendTo(elf)
            -- tar.components.farmplantstress:SetStressed("happiness", false, elf)
            if TheWorld and TheWorld.components.farming_manager then
                local x, y, z = tar:GetPosition():Get()
                TheWorld.components.farming_manager:AddSoilMoistureAtPoint(x, y, z, 10)
                local cx, cz = TheWorld.Map:GetTileCoordsAtPoint(x,0,z)
                TheWorld.components.farming_manager:AddTileNutrients(cx, cz, 5, 5, 5)
            end
        end
    },
    -- add_fuel_to_firepit = {
    --     testfn = function (elf, tar)
    --         return TheWorld.state.isnight and (tar.prefab == 'firepit' or tar.prefab == 'coldfirepit') and tar.components.fueled and tar.components.fueled:IsEmpty() and elf.components.container and elf.components.container:Has('log',1) or false
    --     end,
    --     actionfn = function (elf, tar)
    --         elf.components.container:remove
    --     end
    -- }
}
---comment
---@param elf ent
---@param tar ent
---@return string|nil # 返回helps里的键
local function fn_to_choose_help(elf,tar)
    local tar_prefab = tar.prefab
    if helps[tar_prefab] then
        return tar_prefab
    end
    if tar:HasTag('farm_plant') and tar:HasTag('tendable_farmplant') and tar.components.farmplanttendable ~= nil then -- and tar.components.farmplantstress and tar.components.farmplantstress.stressors and next(tar.components.farmplantstress.stressors) then
        return 'help_farm'
    end
    -- if TheWorld.state.isnight and (tar.prefab == 'firepit' or tar.prefab == 'coldfirepit') and tar.components.fueled and tar.components.fueled:IsEmpty() and elf.components.container and elf.components.container:Has('log',1) then
    --     return 'add_fuel_to_firepit'
    -- end
    return nil
end

local function log(...)
    -- SUGAR_webber_the_trainer:declare(...)
end

local function sleeprdm(time) -- 没有必要的优化: 避免过多小虫在过短时间内同时思考, 500只以上 这个大概就有用了(
    -- Sleep(math.max(.5,time + math.random()*2 - .5))
    Sleep(time)
end

local isTree = SUGAR_webber_the_trainer:stringIncludeOneOfThese('evergreen','deciduoustree')

---@type table<string,fun(inst:ent_webbert_skitter,x:number,y:number,z:number,mx:number,my:number,mz:number,dist:number,player:ent|nil):boolean,string|nil> # 返回为true则代表执行成功,重新思考,false则继续思考
local BH = {
    -- 帮助砍树(需触发)
    choptree = function (inst,x,y,z,mx,my,mz,dist,player)
        if SUGAR_webber_the_trainer:taskIfExist(player,'taskintime_webbert_stop_chop') then
            inst.components.webbert_skitter_misc._task_tree = 10
        else
            inst.components.webbert_skitter_misc._task_tree = nil
        end
        if inst.components.webbert_skitter_misc._task_tree then
            local ents = TheSim:FindEntities(x, y, z, 10, {'tree','shelter'}, {"INLIMBO"})
            -- 挑选目标
            if inst.components.webbert_skitter_misc._tree == nil or not inst.components.webbert_skitter_misc._tree:IsValid() then
                for _,v in pairs(ents) do
                    if v and v:IsValid() and isTree(v.prefab) and v.components.workable and v.components.workable:CanBeWorked() then
                        inst.components.webbert_skitter_misc._tree = v
                        break
                    end
                end
            end
            -- 如果目标有效 且能被工作
            if inst.components.webbert_skitter_misc._tree and inst.components.webbert_skitter_misc._tree:IsValid() and inst.components.webbert_skitter_misc._tree.components.workable and inst.components.webbert_skitter_misc._tree.components.workable:CanBeWorked() then
                if COORDS_webber_the_trainer:calcDistByEnt(inst.components.webbert_skitter_misc._tree,inst,true) < 1.5 then
                    inst.Physics:Stop()
                    inst.AnimState:PlayAnimation('bounce',false)
                    inst.AnimState:PushAnimation('idle_2',true)
                    inst:DoTaskInTime(0.2,function()
                        if inst.components.webbert_skitter_misc._tree and inst.components.webbert_skitter_misc._tree:IsValid() and inst.components.webbert_skitter_misc._tree.components.workable and inst.components.webbert_skitter_misc._tree.components.workable:CanBeWorked() then
                            local tar_x,_,tar_z = inst.components.webbert_skitter_misc._tree:GetPosition():Get()
                            SpawnStrikeFX(2,tar_x,0,tar_z)
                            inst.components.webbert_skitter_misc._tree.components.workable:WorkedBy(inst,2)
                        end
                    end)
                    Annoy(inst,'choptree','chop',.2)
                    sleeprdm(1)
                    return true -- 砍树很快
                else
                    inst.components.locomotor:GoToEntity(inst.components.webbert_skitter_misc._tree)
                    Annoy(inst,'choptree','gototree',.2)
                    sleeprdm(1.5)
                    return true -- 跑向活的速度是很快的 所以这里间隔短一些 不要过去发呆
                end
            else
                -- 丢弃不能工作的目标
                inst.components.webbert_skitter_misc._tree = nil
            end
        else
            -- 任务取消时, 丢弃工作的目标
            inst.components.webbert_skitter_misc._tree = nil
        end
        return false
    end,
    -- 帮助采矿(需触发)
    mining = function (inst, x, y, z,mx,my,mz,dist,player)
        if SUGAR_webber_the_trainer:taskIfExist(player,'taskintime_webbert_stop_mine') then
            inst.components.webbert_skitter_misc._task_mine = 10
        else
            inst.components.webbert_skitter_misc._task_mine = nil
        end
        if inst.components.webbert_skitter_misc._task_mine then
            local ents = TheSim:FindEntities(x, y, z, 10, {'boulder'}, {"INLIMBO"})
            -- 挑选目标
            if inst.components.webbert_skitter_misc._mine == nil or not inst.components.webbert_skitter_misc._mine:IsValid() then
                for _,v in pairs(ents) do
                    if v and v:IsValid() and v.components.workable and v.components.workable:CanBeWorked() then
                        inst.components.webbert_skitter_misc._mine = v
                        break
                    end
                end
            end
            -- 如果目标有效 且能被工作
            if inst.components.webbert_skitter_misc._mine and inst.components.webbert_skitter_misc._mine:IsValid() and inst.components.webbert_skitter_misc._mine.components.workable and inst.components.webbert_skitter_misc._mine.components.workable:CanBeWorked() then
                if COORDS_webber_the_trainer:calcDistByEnt(inst.components.webbert_skitter_misc._mine,inst,true) < 1.5 then
                    inst.Physics:Stop()
                    inst.AnimState:PlayAnimation('bounce',false)
                    inst.AnimState:PushAnimation('idle_2',true)
                    inst:DoTaskInTime(0.2,function()
                        if inst.components.webbert_skitter_misc._mine and inst.components.webbert_skitter_misc._mine:IsValid() and inst.components.webbert_skitter_misc._mine.components.workable and inst.components.webbert_skitter_misc._mine.components.workable:CanBeWorked() then
                            local tar_x,_,tar_z = inst.components.webbert_skitter_misc._mine:GetPosition():Get()
                            SpawnStrikeFX(2,tar_x,0,tar_z)
                            inst.components.webbert_skitter_misc._mine.components.workable:WorkedBy(inst,2)
                        end
                    end)
                    Annoy(inst,'mining','mine',.2)
                    sleeprdm(1)
                    return true -- 砍树很快
                else
                    inst.components.locomotor:GoToEntity(inst.components.webbert_skitter_misc._mine)
                    Annoy(inst,'mining','gotomine',.2)
                    sleeprdm(1.5)
                    return true -- 跑向活的速度是很快的 所以这里间隔短一些 不要过去发呆
                end
            else
                -- 丢弃不能工作的目标
                inst.components.webbert_skitter_misc._mine = nil
            end
        else
            -- 任务取消时, 丢弃工作的目标
            inst.components.webbert_skitter_misc._mine = nil
        end
        return false
    end,
    -- 干小活(自动)
    gather_resource = function (inst, x, y, z,mx,my,mz,dist,player)
        if inst.components.webbert_skitter_misc._grass == nil or not inst.components.webbert_skitter_misc._grass:IsValid() then
            local ents = TheSim:FindEntities(x, y, z, 10, nil, {"INLIMBO"})
            for _,v in pairs(ents) do
                local helps_key = fn_to_choose_help(inst,v)
                local testfn = helps_key and helps[helps_key] and helps[helps_key].testfn
                if testfn and testfn(inst,v) then
                    log('找到了一个小活干')
                    inst.components.webbert_skitter_misc._helps_key = helps_key
                    inst.components.webbert_skitter_misc._grass = v
                    break
                end
            end
        end
        -- 准备干小活
        if inst.components.webbert_skitter_misc._grass and inst.components.webbert_skitter_misc._grass:IsValid() then
            local helps_key = inst.components.webbert_skitter_misc._helps_key
            local testfn = helps_key and helps[helps_key] and helps[helps_key].testfn
            if testfn and testfn(inst,inst.components.webbert_skitter_misc._grass) then
                if COORDS_webber_the_trainer:calcDistByEnt(inst.components.webbert_skitter_misc._grass,inst,true) < 1 then
                    log('到活的附近了,准备干')
                    inst.Physics:Stop()
                    inst.AnimState:PlayAnimation('bounce',false)
                    inst.AnimState:PushAnimation('idle_2',true)
                    inst:DoTaskInTime(0.2,function()
                        if testfn(inst,inst.components.webbert_skitter_misc._grass) then
                            local actionfn = helps_key and helps[helps_key] and helps[helps_key].actionfn
                            if actionfn then
                                log('干')
                                actionfn(inst,inst.components.webbert_skitter_misc._grass)
                            end
                        end
                        inst.components.webbert_skitter_misc._grass = nil
                    end)
                    Annoy(inst,'gather_resource','work',.2)
                    sleeprdm(1)
                    return true -- 干完一次继续快速找一次小活, 而不是找玩家, 防止附近同时存在很多活, 这种情况应优先干活
                else
                    log('我在干活的路上')
                    inst.components.locomotor:GoToEntity(inst.components.webbert_skitter_misc._grass)
                    Annoy(inst,'gather_resource','gotowork',.2,player and player:IsValid() and player:GetDisplayName() or nil)
                    sleeprdm(1.5)
                    return true -- 跑向活的速度是很快的 所以这里间隔短一些 不要过去发呆
                end
            else
                inst.components.webbert_skitter_misc._grass = nil
                inst.components.webbert_skitter_misc._helps_key = nil
                Annoy(inst,'gather_resource','notar',.3)
                sleeprdm(1)
                return true -- 干小活的目标无效,应该重新思考(一般是附近活很多和玩家一起干的时候,自己的活被玩家干了,这时应该找活干而不是跟着玩家)
            end
        end
        return false
    end,
    -- 睡觉 包括 pre 和 loop
    sleep = function (inst, x, y, z,mx,my,mz,dist)
        -- 不是正在睡觉 , 常规判断 , 则睡觉
        if not inst.sg:HasStateTag('sleeping') and not inst.sg:HasStateTag('gotosleep') then
            if TheWorld.state.isnight and not TheWorld.state.isfullmoon and not TheWorld:HasTag("cave") then
                log('准备睡觉')
                inst.sg:GoToState('sleep')
                Annoy(inst,'sleep','sleep_pre',.2)
                sleeprdm(2) -- 实际不应该这么快, 但是我为了播粒子特效, 所以加快思考
                return true
            end
        else
            if inst.components.webbert_skitter_misc._fx_sleep_zzz and inst.components.webbert_skitter_misc._fx_sleep_zzz:IsValid() then
                inst.components.webbert_skitter_misc._fx_sleep_zzz:Remove()
            end
            inst.components.webbert_skitter_misc._fx_sleep_zzz = nil
            inst.components.webbert_skitter_misc._fx_sleep_zzz = SpawnPrefab('particle_webbert_sleep_zzz')
            inst.components.webbert_skitter_misc._fx_sleep_zzz.entity:SetParent(inst.entity)
            log('睡觉 loop')
            Annoy(inst,'sleep','sleep_loop',.3)
            sleeprdm(5)
            return true -- sleeping
        end
        return false
    end,
    -- 起床
    wakeup = function (inst, x, y, z,mx,my,mz,dist)
        local cmp = inst.components.webbert_skitter_misc
        if (inst.sg:HasStateTag('sleeping') or inst.sg:HasStateTag('gotosleep')) then -- 如果在睡觉状态
            if cmp._task_incombat then -- 如果在战斗, 强制唤醒
                inst.sg:GoToState('wakeup')
                if inst.components.webbert_skitter_misc._fx_sleep_zzz and inst.components.webbert_skitter_misc._fx_sleep_zzz:IsValid() then
                    inst.components.webbert_skitter_misc._fx_sleep_zzz:Remove()
                end
                inst.components.webbert_skitter_misc._fx_sleep_zzz = nil
                sleeprdm(.5) -- 快速启动,重新思考
                return true
            end
            if dist > 15 or (TheWorld.state.isday and not TheWorld:HasTag("cave")) then
                inst.sg:GoToState('wakeup')
                if inst.components.webbert_skitter_misc._fx_sleep_zzz and inst.components.webbert_skitter_misc._fx_sleep_zzz:IsValid() then
                    inst.components.webbert_skitter_misc._fx_sleep_zzz:Remove()
                end
                inst.components.webbert_skitter_misc._fx_sleep_zzz = nil
                log('天亮了或者主人离得太远了 都要起来')
                Annoy(inst,'wakeup','wakeup',.7)
                sleeprdm(2)
                return true
            end
        else -- 清空一下把 虽然貌似没必要
            if inst.components.webbert_skitter_misc._fx_sleep_zzz and inst.components.webbert_skitter_misc._fx_sleep_zzz:IsValid() then
                inst.components.webbert_skitter_misc._fx_sleep_zzz:Remove()
            end
            inst.components.webbert_skitter_misc._fx_sleep_zzz = nil
        end
        return false
    end,
    -- 治疗(无寻路)
    heal_anytime = function (inst, x, y, z,mx,my,mz, dist, player)
        local cmp = inst.components.webbert_skitter_misc
        if player and player:IsValid() then
            if player.components.health and player.components.health:GetPercent() < .8 then -- 玩家血量低于80%才触发
                Annoy(inst,'heal_anytime','hplow',.1)
                if dist < 10 then -- 触发时距离不能过远
                    log('距离足够治疗')
                    if cmp._fx_heal_whenfree == nil or not cmp._fx_heal_whenfree:IsValid() then
                        cmp._fx_heal_whenfree = nil
                        cmp._fx_heal_whenfree = SpawnPrefab('fx_webbert_skitter_heallaser')
                        cmp._fx_heal_whenfree.fn_fx_webbert_skitter_heallaser_follow(cmp._fx_heal_whenfree,inst,player,inst.components.webbert_skitter_misc.when_spawn_hp_recovery_player)
                        cmp._fx_heal_whenfree:ForceFacePoint(mx,1,mz)
                    end
                end
            else
                if cmp._fx_heal_whenfree then
                    if cmp._fx_heal_whenfree:IsValid() then
                        cmp._fx_heal_whenfree:Remove()
                    end
                    cmp._fx_heal_whenfree = nil
                end
            end
        end
        return false
    end,
    -- 往玩家身后躲避
    evade = function (inst, x, y, z, mx, my, mz, dist, player)
        local cmp = inst.components.webbert_skitter_misc
        if player and player:IsValid() and player.components.combat then
            local mob = player.components.combat.target
            if mob and mob:IsValid() and mob.components.health and mob.components.combat and not mob.components.combat:IsAlly(player) then
                cmp._task_incombat = true
                SUGAR_webber_the_trainer:taskDoInTime(inst,'task_intime_webbert_skitter_task_incombat',10,function () -- 战斗默认持续10秒
                    cmp._task_incombat = nil
                end,true)
            end
            if cmp._task_incombat then
                local maxdist = 99
                local closest = nil
                local v_x,v_y,v_z = nil,nil,nil
                local ents = TheSim:FindEntities(mx, 0, mz, 6, {'_combat','_health'}, SUGAR_webber_the_trainer.tags_notenemy)
                for _,v in pairs(ents) do
                    if v.components.combat and not v.components.combat:IsAlly(player) then
                        v_x,v_y,v_z = v:GetPosition():Get()
                        local _dist = COORDS_webber_the_trainer:calcDist(v_x,v_z,mx,mz,true)
                        if _dist < maxdist then
                            maxdist = _dist
                            closest = v
                        end
                    end
                end
                if closest and v_x and v_z then
                    local des_x,des_z = COORDS_webber_the_trainer:findEvadePoint(v_x,v_z,mx,mz,70,7,10)
                    inst.components.locomotor:GoToPoint(Vector3(des_x,0,des_z))
                    log('正在躲避到玩家身后')
                    sleeprdm(1)
                    return true
                end
                sleeprdm(2)
                return true -- 只要在战斗状态 就不往下思考了
            end
        end
        return false
    end,
    -- 捡东西 (堆叠的东西不捡, 只捡可堆叠的单个物品, 或者在白名单中的物品)
    -- pickupitems = function (inst, x, y, z, mx, my, mz, dist, player)
    --     local cmp = inst.components.webbert_skitter_misc
    -- end

}

---@class ent_webbert_skitter:ent

local function fn()
    local inst = CreateEntity()

    ---@cast inst ent_webbert_skitter

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    -- inst.entity:AddLight()
    inst.entity:AddMiniMapEntity()
    inst.entity:AddNetwork()
    inst.entity:AddSoundEmitter()
    -- MakeTinyFlyingCharacterPhysics(inst, 1, .5)
    MakeCharacterPhysics(inst, 2, .2)

    inst.AnimState:SetBank('fused_shadeling_bomb')
    inst.AnimState:SetBuild('fused_shadeling_bomb')
    inst.AnimState:PlayAnimation("idle_2",true)
    -- inst.AnimState:PlayAnimation("spawn",false)
    -- inst.AnimState:PushAnimation('idle_2',true)

    -- MakeInventoryFloatable(inst, "med", nil, 0.75)

    -- inst.Light:SetFalloff(0.5)
    -- inst.Light:SetIntensity(.8)
    -- inst.Light:SetRadius(1.3)
    -- inst.Light:SetColour(128/255, 20/255, 128/255)
    -- inst.Light:Enable(true)

    inst.entity:SetPristine()

    inst:AddTag("nosteal")
    inst:AddTag('companion')
    inst:AddTag('NOBLOCK')

    inst:AddComponent('talker')

    -- inst.MiniMapEntity:SetIcon(prefab_id..".tex")

    if not TheWorld.ismastersim then
        return inst
    end

    -- inst:AddComponent("talker")
    inst:AddComponent("inspectable")

    inst:AddComponent("locomotor")
    inst.components.locomotor.walkspeed = 6

    inst:AddComponent('health')
    inst.components.health:SetMaxHealth(100)

    inst:AddComponent('combat')

    inst:AddComponent('container')
    inst.components.container:WidgetSetup(prefab_id)
    -- 绑定
    inst:AddComponent('staff_arachnidnexus_bind')
    -- 虚拟库存 (弃用了, 因为考虑到复杂物品的问题, 所以还是改用容器)
    -- inst:AddComponent('webbert_skitter_inventory')
    -- 杂项
    inst:AddComponent('webbert_skitter_misc')

    inst:AddComponent('named')

    -- 自然恢复
    inst:DoPeriodicTask(3,function ()
        if SUGAR_webber_the_trainer:checkAlive(inst) then
            local base = -.5 + inst.components.webbert_skitter_misc.when_spawn_hp_recovery
            inst.components.health:DoDelta(base,true)
        end
    end)

    inst:DoTaskInTime(2+UnitRand(),function ()
        inst.Physics:Stop()
        inst.components.locomotor:Stop()
        inst:StartThread(function ()
            repeat
                repeat
                    if inst.components.webbert_skitter_misc == nil then
                        Sleep(5)
                        break
                    end
                    if inst.components.webbert_skitter_misc.stop_thinking then
                        sleeprdm(inst.components.webbert_skitter_misc.stop_thinking)
                        break
                    end
                    local x,y,z = inst:GetPosition():Get()
                    ---法杖(主人)
                    local staff = inst.components.staff_arachnidnexus_bind:GetMaster()
                    -- // 是否有临时的主人
                    local temp_master = inst.components.webbert_skitter_misc:GetTempMaster() or nil
                    if temp_master and temp_master:IsValid() then
                        staff = temp_master
                    end
                    -- // 没有任何有效的主人时
                    if staff == nil or not staff:IsValid() then
                        sleeprdm(6)
                        break -- 法杖都不存在的情况下 没有必要频繁思考
                    end
                    local master_x,master_y,master_z = staff:GetPosition():Get()
                    ---法杖在玩家身上时,才有player(有临时主人 用临时的)
                    local player = (temp_master and temp_master:IsValid() and temp_master) or (staff.components.inventoryitem and staff.components.inventoryitem:GetGrandOwner()) or nil
                    ---和法杖的距离(有临时主人 用临时的)
                    local dist_btw_staff = COORDS_webber_the_trainer:calcDist(x,z,master_x,master_z,true)

                    -- // 睡醒了
                    if BH.wakeup(inst,x,0,z,master_x,master_y,master_z,dist_btw_staff) then break end

                    -- // 治疗
                    if BH.heal_anytime(inst,x,0,z,master_x,master_y,master_z,dist_btw_staff,player) then break end

                    -- // 躲到玩家身后
                    if BH.evade(inst,x,0,z,master_x,master_y,master_z,dist_btw_staff,player) then break end

                    -- // 距离太远则强制跟随主人
                    if dist_btw_staff > 50 then -- 过远直接传送至玩家附近
                        local des_x,des_z = COORDS_webber_the_trainer:GenPointInCircle(master_x,master_z,3)() -- 传进一些 避免玩家在海洋附近
                        local cur_tile = TheWorld.Map:GetTileAtPoint(des_x,0,des_z)
                        if cur_tile == 65535 or cur_tile == 1 or (cur_tile >= 201 and cur_tile <= 208) then
                            sleeprdm(2) -- 如果是虚空或海洋 跳过这一轮检测
                            break
                        end
                        inst.Transform:SetPosition(des_x,0,des_z)
                        inst.components.webbert_skitter_misc._task_tree = nil
                        inst.components.webbert_skitter_misc._task_mine = nil
                        inst.components.webbert_skitter_misc._tree = nil
                        inst.components.webbert_skitter_misc._mine = nil
                        inst.components.webbert_skitter_misc._grass = nil
                        sleeprdm(2)
                        break
                    elseif dist_btw_staff > 15 then -- 虽然优先干活, 但是如果距离主人太远时,会强制跟随
                        log("距离主人太远 正在跟随")
                        local des_x,des_z = COORDS_webber_the_trainer:GenPointOnRing(master_x,master_z,4.5)() -- 随机选取的半径要比玩家半径小一些
                        inst.components.locomotor:GoToPoint(Vector3(des_x,0,des_z))
                        inst.components.webbert_skitter_misc._task_tree = nil
                        inst.components.webbert_skitter_misc._task_mine = nil
                        inst.components.webbert_skitter_misc._tree = nil
                        inst.components.webbert_skitter_misc._mine = nil
                        inst.components.webbert_skitter_misc._grass = nil
                        sleeprdm(2)
                        break -- 跟随主人设置个2,3秒差不多了, 间隔太高, 玩家跑太远了追不上, 后续考虑加个距离太远就瞬移
                    end

                    -- // 砍树 需要玩家主动触发
                    if BH.choptree(inst,x,0,z,master_x,master_y,master_z,dist_btw_staff,player) then break end
                    -- // 采矿 需要玩家主动触发
                    if BH.mining(inst,x,0,z,master_x,master_y,master_z,dist_btw_staff,player) then break end
                    -- // 帮忙干小活
                    if BH.gather_resource(inst,x,0,z,master_x,master_y,master_z,dist_btw_staff,player) then break end
                    -- // 睡觉
                    if BH.sleep(inst,x,0,z,master_x,master_y,master_z,dist_btw_staff,player) then break end
                    -- // 跟随主人
                    if dist_btw_staff > 8 then -- 当没有任何事做时,首要目标就是跟随主人,因此距离不能太远
                        log("距离主人太远 正在跟随")
                        local des_x,des_z = COORDS_webber_the_trainer:GenPointOnRing(master_x,master_z,6)() -- 随机选取的半径要比玩家半径小一些
                        inst.components.locomotor:GoToPoint(Vector3(des_x,0,des_z))
                        sleeprdm(3)
                        break -- 跟随主人设置个3秒差不多了, 间隔太高, 玩家跑太远了追不上
                    end
                    -- // wander
                    do
                        local des_x,des_z = COORDS_webber_the_trainer:GenPointOnRing(master_x,master_z,6)()
                        inst.components.locomotor:GoToPoint(Vector3(des_x,0,des_z))
                        sleeprdm(6) -- 重启动的时间间隔久一些, 走到这里基本玩家等于在挂机了, 不需要频繁找活干
                        break
                    end

                    sleeprdm(6) -- 保险
                until true
            until false
        end)
    end)

    inst:ListenForEvent('onopen',function (this, data)
        inst.components.webbert_skitter_misc:StopThinking(3) -- 打开时 暂时停止思考
    end)
    inst:ListenForEvent('onclose',function (this, data)
        inst.components.webbert_skitter_misc:StartThinking()
    end)

    -- 死亡掉落所有物品
    inst:ListenForEvent('death',function (this, data)
        inst.components.webbert_skitter_misc:StopThinking(99) -- 死亡时 永久停止思考
        if inst.components.container then
            inst.components.container:DropEverything(inst:GetPosition(),true)
        end
    end)
    inst:SetStateGraph("SGwebbert_skitter")

    -- inst.OnSave = onsave
    -- inst.OnPreLoad = onpreload

    return inst
end

return Prefab("common/inventory/"..prefab_id, fn, assets, prefabs)